package moe.codeest.enviews;

import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.*;
import ohos.agp.utils.Color;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;

/**
 * Created by codeest on 2016/11/14.
 * <p>
 * 很Q 很弹 duang~ duang~ duang~
 */

public class ENSearchView extends Component implements Component.DrawTask, Component.LayoutRefreshedListener {

    private static final int STATE_SEARCHING = 0;

    private static final int STATE_WAIT = 1;

    private static final int DEFAULT_LINE_COLOR = 0xffffffff;

    private static final int DEFAULT_LINE_WIDTH = 9;

    private static final int DEFAULT_DOT_SIZE = 8;

    private static final int DEFAULT_DURATION = 3000;

    private Paint mPaint, mArcPaint;

    private float mFraction;

    private int mCurrentState;

    private Path mPath, mArcPath;

    private PathMeasure mPathMeasure;

    private RectFloat mRectF;

    private float mWidth, mHeight;

    private float mCenterX, mCenterY;

    private float mPathLength, mCircleRadius;

    private float mCurrentPos[], mCurrentTan[];

    private boolean isDotShowing = true;

    private int mDotSize, mDuration;

    private boolean isInit = false;

    public ENSearchView(Context context) {
        this(context, null);
    }

    public ENSearchView(Context context, AttrSet attrSet) {
        this(context, attrSet, null);
    }

    public ENSearchView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        int lineColor = AttrUtils.getColorFromAttr(attrSet, "search_line_color", DEFAULT_LINE_COLOR);
        int lineWidth = AttrUtils.getDimensionFromAttr(attrSet, "search_line_width", DEFAULT_LINE_WIDTH);
        int dotSize = AttrUtils.getDimensionFromAttr(attrSet, "search_dot_size", DEFAULT_DOT_SIZE);

        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.STROKE_STYLE);
        mPaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        mPaint.setStrokeWidth(lineWidth);
        mPaint.setColor(new Color(lineColor));

        mArcPaint = new Paint();
        mArcPaint.setAntiAlias(true);
        mArcPaint.setStyle(Paint.Style.FILL_STYLE);
        mArcPaint.setColor(new Color(lineColor));

        mDotSize = dotSize;
        mDuration = DEFAULT_DURATION;
        mCurrentState = STATE_WAIT;
        mCurrentPos = new float[2];
        mCurrentTan = new float[2];
        mPath = new Path();
        mArcPath = new Path();
        mPathMeasure = new PathMeasure(mPath, false);

        addDrawTask(this);
        setLayoutRefreshedListener(this);
    }

    @Override
    public void onRefreshed(Component component) {
        mWidth = component.getWidth();
        mHeight = component.getHeight();
        mCenterX = mWidth / 2;
        mCenterY = mHeight / 2;
        mCircleRadius = mWidth / 4;

        mRectF = new RectFloat(mCenterX - 0.95f * mCircleRadius, mCenterY - 0.95f * mCircleRadius,
                mCenterX + 0.95f * mCircleRadius, mCenterY + 0.95f * mCircleRadius);

        mPath.moveTo(mCenterX + 2.2f * mCircleRadius / (float) Math.sqrt(2), mCenterY + 2.2f * mCircleRadius / (float) Math.sqrt(2));
        mPath.lineTo(mCenterX, mCenterY);
        mPath.lineTo(mCenterX - 0.45f * mCircleRadius * (float) Math.sqrt(3), mCenterY + 0.45f * mCircleRadius);
        mPath.lineTo(mCenterX - 0.45f * mCircleRadius * (float) Math.sqrt(3), mCenterY - 0.45f * mCircleRadius);
        mPath.lineTo(mCenterX + 0.45f * mCircleRadius * (float) Math.sqrt(3), mCenterY);
        mPath.lineTo(mCenterX, mCenterY);
        mPath.lineTo(mCenterX + 2.2f * mCircleRadius / (float) Math.sqrt(2), mCenterY + 2.2f * mCircleRadius / (float) Math.sqrt(2));

        mPathMeasure.setPath(mPath, false);
        mPathLength = mPathMeasure.getLength();
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (!isInit) {
            isInit = true;
            onRefreshed(component);
        }
        if (mFraction <= 0.2) { //嗷~ 放大镜手柄收缩
            canvas.drawCircle(mCenterX, mCenterY, mCircleRadius - mCircleRadius * mFraction, mPaint);
            canvas.drawLine(mCenterX + mCircleRadius / (float) Math.sqrt(2) + 1.2f * mCircleRadius / (float) Math.sqrt(2) / 0.2f * mFraction,
                    mCenterY + mCircleRadius / (float) Math.sqrt(2) + 1.2f * mCircleRadius / (float) Math.sqrt(2) / 0.2f * mFraction,
                    mCenterX + 2.2f * mCircleRadius / (float) Math.sqrt(2),
                    mCenterY + 2.2f * mCircleRadius / (float) Math.sqrt(2)
                    , mPaint);
        } else if (mFraction <= 0.8) {
            mPathMeasure.getPosTan(0 + mPathLength / 0.6f * (mFraction - 0.2f), mCurrentPos, mCurrentTan);
            if (mCurrentPos[1] == mCenterY && mCurrentPos[0] <= mCenterX + mCircleRadius / 3 && mCurrentPos[0] >= mCenterX - mCircleRadius / 3) {
                if (isDotShowing) {
                    isDotShowing = false;
                } else {
                    canvas.drawCircle(mCurrentPos[0], mCurrentPos[1], mDotSize, mPaint);    //嗷~ 轨迹中的小球
                    isDotShowing = true;
                }
            } else {
                canvas.drawCircle(mCurrentPos[0], mCurrentPos[1], mDotSize, mPaint);
            }
            if (mFraction <= 0.3) { //嗷~ 内圈粘性部分
                canvas.drawCircle(mCenterX, mCenterY, 0.8f * mCircleRadius + mCircleRadius * 2 * (mFraction - 0.2f), mPaint);
            } else {
                canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mPaint);
            }

            if (mFraction <= 0.35 && mFraction > 0.3) {
                canvas.drawArc(mRectF, new Arc(45 - 55 / 0.05f * (mFraction - 0.3f), 110 / 0.05f * (mFraction - 0.3f), false), mArcPaint);
            } else if (mFraction <= 0.4 && mFraction > 0.35) {
                canvas.drawArc(mRectF, new Arc(45 - 55 / 0.05f * (0.4f - mFraction), 110 / 0.05f * (0.4f - mFraction), false), mArcPaint);
            }

            if (mFraction <= 0.75 && mFraction > 0.7) {  //嗷~ 外圈粘性部分
                mArcPath.reset();
                mArcPath.moveTo(mCenterX + mCircleRadius, mCenterY);
                mArcPath.cubicTo(mCenterX + mCircleRadius + 8 / 0.05f * (mFraction - 0.7f), mCenterY + mCircleRadius / 2 + 8 / 0.05f * (mFraction - 0.7f),
                        mCenterX + mCircleRadius / 2 + 8 / 0.05f * (mFraction - 0.7f), mCenterY + mCircleRadius + 8 / 0.05f * (mFraction - 0.7f),
                        mCenterX, mCenterY + mCircleRadius);
                canvas.drawPath(mArcPath, mPaint);
            } else if (mFraction <= 0.8 && mFraction > 0.75) {
                mArcPath.reset();
                mArcPath.moveTo(mCenterX + mCircleRadius, mCenterY);
                mArcPath.cubicTo(mCenterX + mCircleRadius + 8 / 0.05f * (0.8f - mFraction), mCenterY + mCircleRadius / 2 + 8 / 0.05f * (0.8f - mFraction),
                        mCenterX + mCircleRadius / 2 + 8 / 0.05f * (0.8f - mFraction), mCenterY + mCircleRadius + 8 / 0.05f * (0.8f - mFraction),
                        mCenterX, mCenterY + mCircleRadius);
                canvas.drawPath(mArcPath, mPaint);
            }
        } else {    //嗷~ 放大镜手柄伸长
            canvas.drawCircle(mCenterX, mCenterY, mCircleRadius, mPaint);
            canvas.drawLine(mCenterX + 2.2f * mCircleRadius / (float) Math.sqrt(2) - 1.2f * mCircleRadius / (float) Math.sqrt(2) / 0.2f * (mFraction - 0.8f),
                    mCenterY + 2.2f * mCircleRadius / (float) Math.sqrt(2) - 1.2f * mCircleRadius / (float) Math.sqrt(2) / 0.2f * (mFraction - 0.8f),
                    mCenterX + 2.2f * mCircleRadius / (float) Math.sqrt(2),
                    mCenterY + 2.2f * mCircleRadius / (float) Math.sqrt(2)
                    , mPaint);
        }
    }

    public void start() {
        if (mCurrentState == STATE_SEARCHING) {
            return;
        }
        mCurrentState = STATE_SEARCHING;
        AnimatorValue animatorValue = new AnimatorValue();
        animatorValue.setDuration(mDuration);
        animatorValue.setCurveType(Animator.CurveType.LINEAR);
        animatorValue.setValueUpdateListener((animatorValue1, v) -> {
            mFraction = v;
            invalidate();
        });
        animatorValue.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                mCurrentState = STATE_WAIT;
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });
        animatorValue.start();
    }
}
